package cn.geminis.crypto.csp;

import cn.geminis.crypto.core.util.ByteUtils;
import org.bouncycastle.crypto.CipherParameters;

import java.io.Closeable;

/**
 * @author Allen
 */
public abstract class AbstractBlockCipher implements org.bouncycastle.crypto.BlockCipher, Closeable {

    private boolean padding = true;

    /**
     * 根据密钥值产生加密器密钥参数对象
     *
     * @param key 密钥值，为空时表示使用主密钥
     * @return 密钥参数
     */
    public abstract CipherParameters createParams(byte[] key);

    protected abstract String getAlgorithmIdentifier();

    public abstract int getKeySize();

    public boolean getPadding() {
        return this.padding;
    }

    public void setPadding(boolean value) {
        this.padding = value;
    }

    public byte[] encrypt(byte[] data) {
        return this.encrypt(data, null);
    }

    public byte[] encrypt(byte[] data, byte[] key) {
        CipherParameters params = this.createParams(key);

        byte[] paddingData = this.padding ? ByteUtils.pkcs7Padding(data, this.getBlockSize()) : data;
        byte[] result = new byte[paddingData.length];

        this.reset();
        this.init(true, params);
        int index = 0;
        do {
            int len = this.processBlock(paddingData, index, result, index);
            index += len;
        } while (index < paddingData.length);

        return result;
    }

    public byte[] decrypt(byte[] data) {
        return this.decrypt(data, null);
    }

    public byte[] decrypt(byte[] data, byte[] key) {
        CipherParameters params = this.createParams(key);
        byte[] result = new byte[data.length];

        this.reset();
        this.init(false, params);
        int index = 0;
        do {
            int len = this.processBlock(data, index, result, index);
            index += len;
        } while (index < data.length);

        return this.padding ? ByteUtils.pkcs7UnPadding(result) : result;
    }
}
